/*
 * Copyright (C) 2010 Johan Waldeback
 *  
 * This file is part of the OpenFMS project (http://www.openfms-project.org)
 * 
 * OpenFMS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */


#include "GraphCtrl.h"
#include <wx/wx.h>
#include <cassert>

using namespace OpenFms;

/**
 * Fills an array with a sequence with equally spaced values.
 *
 * The first value in the array will be assigned the value a, 
 * and the last value in the array will be assigned the value b. 
 * The values in between will be linearly interpolated between these values.
 *
 * @param[out] p Pointer to target array to be set.
 * @param[in] n Length of the array.
 * @param[in] a The value the first element in the array should be set to.
 * @param[in] b The value the last element in the array should be set to.
 */
static void range( float *p, size_t n, float a, float b )
{
	// assert input values
	assert( p != NULL );
	assert( n > 0 );

	// for each value to set: interpolate between a and b
	for( size_t i=0; i<n; ++i ) {
		p[i] = static_cast<float>(n-i-1)/(n-1) * a + static_cast<float>(i)/(n-1) * b; 
	}
}

/**
 * OpenFms::GraphCtrl constructor
 */
GraphCtrl::GraphCtrl( wxWindow *parent, wxWindowID id) : 
	wxWindow(parent, id)	
{
	Connect(wxEVT_PAINT, wxPaintEventHandler(GraphCtrl::OnPaint));
	Connect(wxEVT_SIZE, wxSizeEventHandler(GraphCtrl::OnSize));

	const int n = 20;

	float x[n], y[n];
	range( x, n, -4.f, 4.f );
	for( int i=0; i<n; ++i ) {
		y[i] = sinf(x[i]);
	}
	this->setData( x, y, n );
}

/**
 * Callback funtion, handles the painting of the graph.
 */
void GraphCtrl::OnPaint(wxPaintEvent& evt)
{
	// Get handle to DC
	wxPaintDC dc(this);

	// Draw background.
	// (a light yellow filled rectangle covering the entire area of the control
	wxSize size = GetSize();
	dc.SetPen(wxPen(wxColour(255, 255, 184))); 
	dc.SetBrush(wxBrush(wxColour(255, 255, 184)));
	dc.DrawRectangle(0, 0, size.GetWidth(), size.GetHeight());


	// Set which margins to use
	// Get min/max values of axes to use
	const int margin = 10, hooklen = 5;
	const float xmax = m_data.getMaxAbsX();
	const float ymax = m_data.getMaxAbsY();

	// Draw x- and y-axes
	dc.SetPen(wxPen(wxColour(0,0,0)));
	dc.DrawLine( 0, size.GetHeight()/2, size.GetWidth()-1, size.GetHeight()/2 );
	dc.DrawLine( size.GetWidth()/2, 0, size.GetWidth()/2, size.GetHeight()-1 );
	dc.DrawLine( margin, size.GetHeight()/2, margin, size.GetHeight()/2 + hooklen );
	dc.DrawLine( size.GetWidth()-margin, size.GetHeight()/2, size.GetWidth()-margin, size.GetHeight()/2 + hooklen );
	dc.DrawLine( size.GetWidth()/2, margin, size.GetWidth()/2+hooklen, margin);
	dc.DrawLine( size.GetWidth()/2, size.GetHeight()-margin, size.GetWidth()/2+hooklen, size.GetHeight()-margin);

	// print value labels
	TCHAR buffer[30];
	_stprintf(buffer, _T("%f"), xmax);
	dc.DrawText( buffer, margin, margin + size.GetHeight()/2 );
	_stprintf(buffer, _T("%f"), ymax);
	dc.DrawText( buffer, margin + size.GetWidth()/2, margin );

	// Draw the data points.
	dc.SetPen(wxPen(wxColour(128, 128, 192)));
	dc.DrawLines( 
		m_data.getScaledWxPointList( (size.GetWidth()-margin)/2 * 1.f/xmax, -(size.GetHeight()-margin)/2 * 1.f/ymax ) , 
		size.GetWidth()/2, size.GetHeight()/2 );
	
}

/**
 * Trigger repaint on resize
 */
void GraphCtrl::OnSize(wxSizeEvent& event)
{
	Refresh();
}

/**
 * Set the list of data points to use
 * @note Just passed the data on to the member instance of OpenFms::GrapDataSet
 * that handles the data point storage
 * @param px Pointer of a list of x-coordinates to use
 * @param py Pointer of a list of y-coordinates to use.
 * @param count Number of points stored in (px,py)
 */
void GraphCtrl::setData( float *px, float *py, int count )
{
	m_data.setData( px, py, count );
}






